#pragma once

#include "UI\ChessPanel.h"
#include "Game\Engine.h"
#include "NewGame.h"

#include <map>
#include <string>
using namespace std;

namespace Chess {

	using namespace System;
	using namespace System::ComponentModel;
	using namespace System::Collections;
	using namespace System::Collections::Generic;
	using namespace System::Windows::Forms;
	using namespace System::Data;
	using namespace System::Drawing;
	using namespace Core;

	/// <summary>
	/// Summary for MainForm
	/// </summary>
	public ref class MainForm : public System::Windows::Forms::Form
	{
	public:
		MainForm(void)
		{
			InitializeComponent();
			//
			//TODO: Add the constructor code here
			//
			_started = false;
			_finished = false;

			_imagePaths = gcnew Dictionary<int, String^>();
			_imagePaths->Add((int)ChPawn + (int)ChWhite * 10, "Images/Classic/WhitePawnSmall.png");
			_imagePaths->Add((int)ChPawn + (int)ChBlack * 10, "Images/Classic/BlackPawnSmall.png");
			_imagePaths->Add((int)ChKing + (int)ChWhite * 10, "Images/Classic/WhiteKingSmall.png");
			_imagePaths->Add((int)ChKing + (int)ChBlack * 10, "Images/Classic/BlackKingSmall.png");
			_imagePaths->Add((int)ChQueen + (int)ChWhite * 10, "Images/Classic/WhiteQueenSmall.png");
			_imagePaths->Add((int)ChQueen + (int)ChBlack * 10, "Images/Classic/BlackQueenSmall.png");
			_imagePaths->Add((int)ChBishop + (int)ChWhite * 10, "Images/Classic/WhiteBishopSmall.png");
			_imagePaths->Add((int)ChBishop + (int)ChBlack * 10, "Images/Classic/BlackBishopSmall.png");
			_imagePaths->Add((int)ChKnight + (int)ChWhite * 10, "Images/Classic/WhiteKnightSmall.png");
			_imagePaths->Add((int)ChKnight + (int)ChBlack * 10, "Images/Classic/BlackKnightSmall.png");
			_imagePaths->Add((int)ChRook + (int)ChWhite * 10, "Images/Classic/WhiteRookSmall.png");
			_imagePaths->Add((int)ChRook + (int)ChBlack * 10, "Images/Classic/BlackRookSmall.png");
		}

	protected:
		/// <summary>
		/// Clean up any resources being used.
		/// </summary>
		~MainForm()
		{
			if (components)
			{
				delete components;
			}
		}
	private: System::Windows::Forms::MenuStrip^  menuStrip1;
	protected: 
	private: System::Windows::Forms::ToolStripMenuItem^  gameToolStripMenuItem;
	private: System::Windows::Forms::ToolStripMenuItem^  newToolStripMenuItem;
	private: System::Windows::Forms::ToolStripMenuItem^  loadToolStripMenuItem;

	private: System::Windows::Forms::ToolStripSeparator^  toolStripMenuItem1;

	private: System::Windows::Forms::ToolStripMenuItem^  helpToolStripMenuItem;
	private: System::Windows::Forms::ToolStripMenuItem^  aboutToolStripMenuItem;
	private: System::Windows::Forms::Panel^  pnlBoard;
	private: System::Windows::Forms::Label^  lblWhiteTime;
	private: System::Windows::Forms::Label^  lblBlackTime;
	private: System::Windows::Forms::Label^  lblTimeLimit;



	private: System::Windows::Forms::Timer^  turnTimer;
	private: System::Windows::Forms::SaveFileDialog^  saveFileDialog1;
	private: System::Windows::Forms::OpenFileDialog^  openFileDialog1;
	private: System::Windows::Forms::StatusStrip^  statusStrip1;
	private: System::Windows::Forms::ToolStripMenuItem^  undoToolStripMenuItem;
	private: System::Windows::Forms::ToolStripMenuItem^  redoToolStripMenuItem;
	private: System::Windows::Forms::ToolStripSeparator^  toolStripMenuItem2;
	private: System::Windows::Forms::ToolStripMenuItem^  exitToolStripMenuItem;
	private: System::Windows::Forms::ToolStripStatusLabel^  lblStatus;
	private: System::Windows::Forms::ToolStripProgressBar^  toolStripProgressBar1;
	private: System::Windows::Forms::ToolStripMenuItem^  saveToolStripMenuItem;

	private: System::Windows::Forms::ToolStripSeparator^  toolStripSeparator1;
	private: System::ComponentModel::IContainer^  components;


	protected: 

	private:
		/// <summary>
		/// Required designer variable.
		/// </summary>



#pragma region Windows Form Designer generated code
		/// <summary>
		/// Required method for Designer support - do not modify
		/// the contents of this method with the code editor.
		/// </summary>
		void InitializeComponent(void)
		{
			this->components = (gcnew System::ComponentModel::Container());
			this->menuStrip1 = (gcnew System::Windows::Forms::MenuStrip());
			this->gameToolStripMenuItem = (gcnew System::Windows::Forms::ToolStripMenuItem());
			this->newToolStripMenuItem = (gcnew System::Windows::Forms::ToolStripMenuItem());
			this->toolStripSeparator1 = (gcnew System::Windows::Forms::ToolStripSeparator());
			this->saveToolStripMenuItem = (gcnew System::Windows::Forms::ToolStripMenuItem());
			this->loadToolStripMenuItem = (gcnew System::Windows::Forms::ToolStripMenuItem());
			this->toolStripMenuItem1 = (gcnew System::Windows::Forms::ToolStripSeparator());
			this->undoToolStripMenuItem = (gcnew System::Windows::Forms::ToolStripMenuItem());
			this->redoToolStripMenuItem = (gcnew System::Windows::Forms::ToolStripMenuItem());
			this->toolStripMenuItem2 = (gcnew System::Windows::Forms::ToolStripSeparator());
			this->exitToolStripMenuItem = (gcnew System::Windows::Forms::ToolStripMenuItem());
			this->helpToolStripMenuItem = (gcnew System::Windows::Forms::ToolStripMenuItem());
			this->aboutToolStripMenuItem = (gcnew System::Windows::Forms::ToolStripMenuItem());
			this->pnlBoard = (gcnew System::Windows::Forms::Panel());
			this->lblWhiteTime = (gcnew System::Windows::Forms::Label());
			this->lblBlackTime = (gcnew System::Windows::Forms::Label());
			this->lblTimeLimit = (gcnew System::Windows::Forms::Label());
			this->turnTimer = (gcnew System::Windows::Forms::Timer(this->components));
			this->saveFileDialog1 = (gcnew System::Windows::Forms::SaveFileDialog());
			this->openFileDialog1 = (gcnew System::Windows::Forms::OpenFileDialog());
			this->statusStrip1 = (gcnew System::Windows::Forms::StatusStrip());
			this->lblStatus = (gcnew System::Windows::Forms::ToolStripStatusLabel());
			this->toolStripProgressBar1 = (gcnew System::Windows::Forms::ToolStripProgressBar());
			this->menuStrip1->SuspendLayout();
			this->statusStrip1->SuspendLayout();
			this->SuspendLayout();
			// 
			// menuStrip1
			// 
			this->menuStrip1->Items->AddRange(gcnew cli::array< System::Windows::Forms::ToolStripItem^  >(2) {this->gameToolStripMenuItem, 
				this->helpToolStripMenuItem});
			this->menuStrip1->Location = System::Drawing::Point(0, 0);
			this->menuStrip1->Name = L"menuStrip1";
			this->menuStrip1->Size = System::Drawing::Size(811, 24);
			this->menuStrip1->TabIndex = 0;
			this->menuStrip1->Text = L"menuStrip1";
			// 
			// gameToolStripMenuItem
			// 
			this->gameToolStripMenuItem->DropDownItems->AddRange(gcnew cli::array< System::Windows::Forms::ToolStripItem^  >(9) {this->newToolStripMenuItem, 
				this->toolStripSeparator1, this->saveToolStripMenuItem, this->loadToolStripMenuItem, this->toolStripMenuItem1, this->undoToolStripMenuItem, 
				this->redoToolStripMenuItem, this->toolStripMenuItem2, this->exitToolStripMenuItem});
			this->gameToolStripMenuItem->Name = L"gameToolStripMenuItem";
			this->gameToolStripMenuItem->Size = System::Drawing::Size(50, 20);
			this->gameToolStripMenuItem->Text = L"&Game";
			// 
			// newToolStripMenuItem
			// 
			this->newToolStripMenuItem->Name = L"newToolStripMenuItem";
			this->newToolStripMenuItem->ShortcutKeys = System::Windows::Forms::Keys::F2;
			this->newToolStripMenuItem->Size = System::Drawing::Size(144, 22);
			this->newToolStripMenuItem->Text = L"&New";
			this->newToolStripMenuItem->Click += gcnew System::EventHandler(this, &MainForm::newToolStripMenuItem_Click);
			// 
			// toolStripSeparator1
			// 
			this->toolStripSeparator1->Name = L"toolStripSeparator1";
			this->toolStripSeparator1->Size = System::Drawing::Size(141, 6);
			// 
			// saveToolStripMenuItem
			// 
			this->saveToolStripMenuItem->Enabled = false;
			this->saveToolStripMenuItem->Name = L"saveToolStripMenuItem";
			this->saveToolStripMenuItem->ShortcutKeys = static_cast<System::Windows::Forms::Keys>((System::Windows::Forms::Keys::Control | System::Windows::Forms::Keys::S));
			this->saveToolStripMenuItem->Size = System::Drawing::Size(144, 22);
			this->saveToolStripMenuItem->Text = L"&Save";
			this->saveToolStripMenuItem->Click += gcnew System::EventHandler(this, &MainForm::saveToolStripMenuItem_Click);
			// 
			// loadToolStripMenuItem
			// 
			this->loadToolStripMenuItem->Name = L"loadToolStripMenuItem";
			this->loadToolStripMenuItem->ShortcutKeys = static_cast<System::Windows::Forms::Keys>((System::Windows::Forms::Keys::Control | System::Windows::Forms::Keys::O));
			this->loadToolStripMenuItem->Size = System::Drawing::Size(144, 22);
			this->loadToolStripMenuItem->Text = L"&Load";
			this->loadToolStripMenuItem->Click += gcnew System::EventHandler(this, &MainForm::loadToolStripMenuItem_Click);
			// 
			// toolStripMenuItem1
			// 
			this->toolStripMenuItem1->Name = L"toolStripMenuItem1";
			this->toolStripMenuItem1->Size = System::Drawing::Size(141, 6);
			// 
			// undoToolStripMenuItem
			// 
			this->undoToolStripMenuItem->Enabled = false;
			this->undoToolStripMenuItem->Name = L"undoToolStripMenuItem";
			this->undoToolStripMenuItem->ShortcutKeys = static_cast<System::Windows::Forms::Keys>((System::Windows::Forms::Keys::Control | System::Windows::Forms::Keys::Z));
			this->undoToolStripMenuItem->Size = System::Drawing::Size(144, 22);
			this->undoToolStripMenuItem->Text = L"&Undo";
			this->undoToolStripMenuItem->Click += gcnew System::EventHandler(this, &MainForm::undoToolStripMenuItem_Click);
			// 
			// redoToolStripMenuItem
			// 
			this->redoToolStripMenuItem->Enabled = false;
			this->redoToolStripMenuItem->Name = L"redoToolStripMenuItem";
			this->redoToolStripMenuItem->ShortcutKeys = static_cast<System::Windows::Forms::Keys>((System::Windows::Forms::Keys::Control | System::Windows::Forms::Keys::Y));
			this->redoToolStripMenuItem->Size = System::Drawing::Size(144, 22);
			this->redoToolStripMenuItem->Text = L"&Redo";
			this->redoToolStripMenuItem->Click += gcnew System::EventHandler(this, &MainForm::redoToolStripMenuItem_Click);
			// 
			// toolStripMenuItem2
			// 
			this->toolStripMenuItem2->Name = L"toolStripMenuItem2";
			this->toolStripMenuItem2->Size = System::Drawing::Size(141, 6);
			// 
			// exitToolStripMenuItem
			// 
			this->exitToolStripMenuItem->Name = L"exitToolStripMenuItem";
			this->exitToolStripMenuItem->ShortcutKeys = static_cast<System::Windows::Forms::Keys>((System::Windows::Forms::Keys::Alt | System::Windows::Forms::Keys::F4));
			this->exitToolStripMenuItem->Size = System::Drawing::Size(144, 22);
			this->exitToolStripMenuItem->Text = L"E&xit";
			this->exitToolStripMenuItem->Click += gcnew System::EventHandler(this, &MainForm::exitToolStripMenuItem_Click);
			// 
			// helpToolStripMenuItem
			// 
			this->helpToolStripMenuItem->DropDownItems->AddRange(gcnew cli::array< System::Windows::Forms::ToolStripItem^  >(1) {this->aboutToolStripMenuItem});
			this->helpToolStripMenuItem->Name = L"helpToolStripMenuItem";
			this->helpToolStripMenuItem->Size = System::Drawing::Size(44, 20);
			this->helpToolStripMenuItem->Text = L"&Help";
			// 
			// aboutToolStripMenuItem
			// 
			this->aboutToolStripMenuItem->Name = L"aboutToolStripMenuItem";
			this->aboutToolStripMenuItem->Size = System::Drawing::Size(107, 22);
			this->aboutToolStripMenuItem->Text = L"&About";
			// 
			// pnlBoard
			// 
			this->pnlBoard->BackgroundImageLayout = System::Windows::Forms::ImageLayout::Center;
			this->pnlBoard->Location = System::Drawing::Point(12, 68);
			this->pnlBoard->Name = L"pnlBoard";
			this->pnlBoard->Padding = System::Windows::Forms::Padding(2);
			this->pnlBoard->Size = System::Drawing::Size(565, 565);
			this->pnlBoard->TabIndex = 1;
			// 
			// lblWhiteTime
			// 
			this->lblWhiteTime->AutoSize = true;
			this->lblWhiteTime->Font = (gcnew System::Drawing::Font(L"Microsoft Sans Serif", 8.25F, System::Drawing::FontStyle::Bold, System::Drawing::GraphicsUnit::Point, 
				static_cast<System::Byte>(0)));
			this->lblWhiteTime->Location = System::Drawing::Point(12, 42);
			this->lblWhiteTime->Name = L"lblWhiteTime";
			this->lblWhiteTime->Size = System::Drawing::Size(98, 13);
			this->lblWhiteTime->TabIndex = 2;
			this->lblWhiteTime->Text = L"White: 00:00:00";
			// 
			// lblBlackTime
			// 
			this->lblBlackTime->AutoSize = true;
			this->lblBlackTime->Font = (gcnew System::Drawing::Font(L"Microsoft Sans Serif", 8.25F, System::Drawing::FontStyle::Regular, System::Drawing::GraphicsUnit::Point, 
				static_cast<System::Byte>(0)));
			this->lblBlackTime->Location = System::Drawing::Point(132, 42);
			this->lblBlackTime->Name = L"lblBlackTime";
			this->lblBlackTime->Size = System::Drawing::Size(82, 13);
			this->lblBlackTime->TabIndex = 3;
			this->lblBlackTime->Text = L"Black: 00:00:00";
			// 
			// lblTimeLimit
			// 
			this->lblTimeLimit->AutoSize = true;
			this->lblTimeLimit->Location = System::Drawing::Point(235, 41);
			this->lblTimeLimit->Name = L"lblTimeLimit";
			this->lblTimeLimit->Size = System::Drawing::Size(37, 13);
			this->lblTimeLimit->TabIndex = 4;
			this->lblTimeLimit->Text = L"Limit: -";
			// 
			// turnTimer
			// 
			this->turnTimer->Tick += gcnew System::EventHandler(this, &MainForm::turnTimer_Tick);
			// 
			// saveFileDialog1
			// 
			this->saveFileDialog1->Filter = L"Chess Data Files|*.chd";
			this->saveFileDialog1->Title = L"Save Chess Game";
			// 
			// openFileDialog1
			// 
			this->openFileDialog1->Filter = L"Chess Data Files|*.chd";
			this->openFileDialog1->Title = L"Select a Chess File";
			// 
			// statusStrip1
			// 
			this->statusStrip1->Items->AddRange(gcnew cli::array< System::Windows::Forms::ToolStripItem^  >(2) {this->lblStatus, this->toolStripProgressBar1});
			this->statusStrip1->Location = System::Drawing::Point(0, 643);
			this->statusStrip1->Name = L"statusStrip1";
			this->statusStrip1->Size = System::Drawing::Size(811, 22);
			this->statusStrip1->TabIndex = 5;
			this->statusStrip1->Text = L"statusStrip1";
			// 
			// lblStatus
			// 
			this->lblStatus->Name = L"lblStatus";
			this->lblStatus->Size = System::Drawing::Size(39, 17);
			this->lblStatus->Text = L"Ready";
			// 
			// toolStripProgressBar1
			// 
			this->toolStripProgressBar1->Alignment = System::Windows::Forms::ToolStripItemAlignment::Right;
			this->toolStripProgressBar1->AutoSize = false;
			this->toolStripProgressBar1->Name = L"toolStripProgressBar1";
			this->toolStripProgressBar1->Size = System::Drawing::Size(100, 16);
			this->toolStripProgressBar1->Visible = false;
			// 
			// MainForm
			// 
			this->AutoScaleDimensions = System::Drawing::SizeF(6, 13);
			this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font;
			this->ClientSize = System::Drawing::Size(811, 665);
			this->Controls->Add(this->statusStrip1);
			this->Controls->Add(this->lblTimeLimit);
			this->Controls->Add(this->lblBlackTime);
			this->Controls->Add(this->lblWhiteTime);
			this->Controls->Add(this->pnlBoard);
			this->Controls->Add(this->menuStrip1);
			this->MainMenuStrip = this->menuStrip1;
			this->MinimumSize = System::Drawing::Size(602, 682);
			this->Name = L"MainForm";
			this->StartPosition = System::Windows::Forms::FormStartPosition::CenterScreen;
			this->Text = L"Chess";
			this->FormClosing += gcnew System::Windows::Forms::FormClosingEventHandler(this, &MainForm::MainForm_FormClosing);
			this->Load += gcnew System::EventHandler(this, &MainForm::MainForm_Load);
			this->menuStrip1->ResumeLayout(false);
			this->menuStrip1->PerformLayout();
			this->statusStrip1->ResumeLayout(false);
			this->statusStrip1->PerformLayout();
			this->ResumeLayout(false);
			this->PerformLayout();

		}
#pragma endregion

	private:
		static const int TILE_SIZE = 70;
		// class member array of Panels to track chessboard tiles
		Dictionary<int, String^>^ _imagePaths;
		array<ChessPanel^, 2>^ _chessPanels;
		ChessPanel^ _selectedPanel;
		Dictionary<int, ChessPanel^>^ _validPanels;
		int _timeLimitMinutes;
		DateTime _turnTick;
		TimeSpan _whiteTime;
		TimeSpan _blackTime;
		bool _started;
		bool _finished;

		String^ WhosTurnStr() { return WhitesTurn() ? "White" : "Black"; }
		bool WhitesTurn() { return Engine::instance()->whosPlaying() == ChWhite; }
		bool BlacksTurn() { return Engine::instance()->whosPlaying() == ChBlack; }
		void TurnChanged();
		void PrepareBoard();
		void UpdateMove(const Core::Move *mv);
		void ConsiderOverallStatus();
		void New(int mode, int time);
		void LoadGame();
		void SaveGame();
		Square * GetSquareAt(int row, int col);
		Square * GetSquareByKey(int key);
		void PanelSelected(ChessPanel^ selected);
		void HideValidMoves();
		void ShowValidMoves();
		void PerformMove(int row, int col);
		void Undo();
		void Redo();
		void Finish();

		System::Void MainForm_Load(System::Object^  sender, System::EventArgs^  e) 
		{
			_selectedPanel = nullptr;
			_validPanels = gcnew Dictionary<int, ChessPanel^>();
			_chessPanels = gcnew array<ChessPanel^, 2>(Chessboard::RANKS, Chessboard::COLUMNS);

			// double for loop to handle all rows and columns
			for (int x = 0; x < Chessboard::RANKS; x++)
				for (int y = 0; y < Chessboard::COLUMNS; y++)
				{
					// create new Panel control which will be one 
					// chess board tile
					ChessPanel^ newPanel = gcnew ChessPanel(y, x);
					newPanel->Size = System::Drawing::Size(TILE_SIZE, TILE_SIZE);
					newPanel->Location = Point(TILE_SIZE * x, TILE_SIZE * y);

					// add to Form's Controls so that they show up
					pnlBoard->Controls->Add(newPanel);

					// add to our 2d array of panels for future use
					_chessPanels[y, x] = newPanel;

					// color the backgrounds
					newPanel->BackColor = (x+y) % 2 == 0 ? Color::DarkGray : Color::White;
					newPanel->BackgroundImageLayout = System::Windows::Forms::ImageLayout::Center;

					newPanel->MouseDown += gcnew System::Windows::Forms::MouseEventHandler(this, &MainForm::squarePnl_MouseDown);
				}

				//_chessPanels(0, 0)->BackgroundImage = Image::FromFile(_imagePaths[(int)ChPawn + 10 * (int)ChBlack]);
				//_chessPanels(4, 1)->BackgroundImage = Image::FromFile(_imagePaths[(int)ChPawn + 10 * (int)ChWhite]);
		}

		System::Void turnTimer_Tick(System::Object^  sender, System::EventArgs^  e) 
		{
			if(WhitesTurn())
				_whiteTime = _whiteTime.Add(DateTime::Now - _turnTick);
			else if(BlacksTurn())
				_blackTime = _blackTime.Add(DateTime::Now - _turnTick);

			lblWhiteTime->Text = "White: " + (_whiteTime.ToString()->Substring(0, 8));
			lblBlackTime->Text = "Black: " + (_blackTime.ToString()->Substring(0, 8));

			// make bold
			TurnChanged();

			_turnTick = DateTime::Now;
			if(_timeLimitMinutes > 0 && (_whiteTime.Add(_blackTime).TotalMinutes >= _timeLimitMinutes))
				Finish();
		}

		System::Void squarePnl_MouseDown(System::Object^  sender, System::Windows::Forms::MouseEventArgs^  e) 
		{
			if(_finished)
				return;
			if(Engine::humans() == 1 && Engine::instance()->whosPlaying() == ChBlack)
				return;
			ChessPanel^ pnl = (ChessPanel^)sender;
			PanelSelected(pnl);
		}

		System::Void newToolStripMenuItem_Click(System::Object^  sender, System::EventArgs^  e) 
		{
			NewGame^ frm = gcnew NewGame();
			if(frm->ShowDialog() == System::Windows::Forms::DialogResult::OK)
			{
				New(frm->Mode(), frm->TimeLimit());
				PrepareBoard();
			}
		}

		System::Void NewAgainstToolStripMenuItem_Click(System::Object^  sender, System::EventArgs^  e) 
		{
		}

		System::Void loadToolStripMenuItem_Click(System::Object^  sender, System::EventArgs^  e) 
		{
			LoadGame();
		}


		System::Void saveToolStripMenuItem_Click(System::Object^  sender, System::EventArgs^  e) 
		{
			SaveGame();
		}

		System::Void exitToolStripMenuItem_Click(System::Object^  sender, System::EventArgs^  e) 
		{
			this->Close();
		}

		System::Void MainForm_FormClosing(System::Object^  sender, System::Windows::Forms::FormClosingEventArgs^  e) 
		{
			if(!_started)
				return;
			System::Windows::Forms::DialogResult dr = 
				MessageBox::Show("Are you sure, exit without saving?", "Exiting...", MessageBoxButtons::YesNo, MessageBoxIcon::Question);
			if(dr == System::Windows::Forms::DialogResult::No)
				e->Cancel = true;
		}

		System::Void undoToolStripMenuItem_Click(System::Object^  sender, System::EventArgs^  e) 
		{
			if(_finished)
				return;
			Undo();
		}

		System::Void redoToolStripMenuItem_Click(System::Object^  sender, System::EventArgs^  e) 
		{
			if(_finished)
				return;
			Redo();
		}
};
}
